package shared;


import java.util.List;
import java.util.Vector;

import lock.ConcreteLock;
import lock.Lock;

public class Buffer<T> {
	
	private final List<T> data;
	private final Lock lock;
	private final Lock criticalSection;
	
	/**
	 * Constructor of {@link Buffer}.
	 */
	public Buffer(){
		this.data = new Vector<T>();
		this.lock = new ConcreteLock(true);
		this.criticalSection = new ConcreteLock(false);
	}

	/**
	 * Adds a value to the top of this buffer.
	 * @param object is the value that is added.
	 */
	public void put(final T object) {
		this.criticalSection.lock();
		this.data.add(object);
		this.lock.unlock();
		this.criticalSection.unlock();
	}

	/**
	 * Provides the value from the bottom of this buffer.
	 * If there is no value in this buffer, waits until a value is put inside this buffer.
	 * The value that is returned is removed from this buffer.
	 * @return the value from the bottom of this buffer.
	 */
	public T get() {
		this.lock.lock();
		this.criticalSection.lock();
		final T result = this.data.remove(0);
		if (!data.isEmpty()) this.lock.unlock();
		this.criticalSection.unlock();
		return result;
	}
	
	public T peek(){
		this.lock.lock();
		this.criticalSection.lock();
		final T result = this.data.get(0);
		this.lock.unlock();
		this.criticalSection.unlock();
		return result;
	}


	public boolean isEmpty() {
		return this.data.isEmpty();
	}
	
	@Override
	public Buffer<T> clone(){
		final Buffer<T> clone = new Buffer<T>();
		this.criticalSection.lock();
		for(final T data : this.data){
			clone.put(data);
		}
		this.criticalSection.unlock();
		return clone;
	}

}
